<?php


namespace app\service\alone\Excel;


use app\service\alone\BaseService;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\IOFactory;

class ImportService extends BaseService
{
    /** @var string $fileName 文件名称（绝对路径） */
    private $fileName;

    protected function init()
    {
        $this->fileName = $this->data['fileName'];
    }

    /**
     * 分段读取 读取excel表中内容
     *
     * @param array $sheets [ ['index' => '工作薄索引', 'rows' => ['start' => '开始行', 'end' => '第一次读取总行数', 'step' => '一次加载行数', 'call' => '回调函数 function ($data) {}' ] ] ]
     * @param array $column 读取的列
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     */
    public function segment(array $sheets, array $column): void
    {
        $reader = IOFactory::createReaderForFile($this->fileName);
        $info = $reader->listWorksheetInfo($this->fileName);

        foreach ($sheets as $v) {
            $rows = [
                'start' => $v['rows']['start'],
                'end' => $v['rows']['end'],
                'total' => (int)$info[$v['index']]['totalRows'],
            ];

            do {
                // 仅读取指定行数
                $reader->setReadFilter(new ReadFilter(['start' => $rows['start'], 'end' => $rows['end']], $column));

                // 仅读取指定 sheet 薄
                $reader->setLoadSheetsOnly([$info[$v['index']]['worksheetName']]);

                // 仅读取数据，忽略样式等
                $reader->setReadDataOnly(true);

                // 读取文件，并处理用户回调
                $spreadsheet = $reader->load($this->fileName);
                call_user_func($v['call'], array_slice($spreadsheet->getActiveSheet()->toArray(null, false, false), $rows['start'] - 1, $rows['end'] - $rows['start'] + 1));

                // 清除读取的 sheet 薄，释放内存
                $spreadsheet->disconnectWorksheets();
                unset($spreadsheet);

                $rows['start'] = $rows['end'] + 1;
                $rows['end'] = $rows['end'] === $rows['total'] ? false : min($rows['end'] + $v['rows']['step'], $rows['total']);
            } while ($rows['end'] !== false);
        }
    }

    /**
     * 全部加载 读取excel表中内容
     *
     * @param int $startRow 开始行
     * @param int $startColumn 开始列
     * @return array
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     */
    public function all(int $startRow = 1, int $startColumn = 1): array
    {
        $excel = IOFactory::load($this->fileName);

        $worksheet = $excel->getActiveSheet();
        $highestRow = $worksheet->getHighestRow(); // 总行数
        $highestColumn = $worksheet->getHighestColumn(); // 总列数
        $highestColumnIndex = Coordinate::columnIndexFromString($highestColumn); // e.g. 5

        // 验证是否有数据
        if ($highestRow - ($startRow - 1) <= 0) return echoArr(500, '当前文件数据为空');

        try {
            $list = array_reduce(range($startRow, $highestRow), function ($result, $row) use ($worksheet, $highestColumnIndex, $startColumn) {
                $column = array_reduce(range($startColumn, $highestColumnIndex), function ($single, $column) use ($worksheet, $row) {
                    array_push($single, $worksheet->getCellByColumnAndRow($column, $row)->getFormattedValue());

                    return $single;
                }, []);

                if ($column) array_push($result, $column);

                return $result;
            }, []);
        } catch (\Exception $exception) {
            return echoArr(500, '数据格式有误，请重新上传');
        }

        return echoArr(200, '读取成功', [
            'list' => $list
        ]);
    }
}